package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.common.LoginCode;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;

import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.entity.SetmealDish;
import com.itheima.reggie.exception.CustomException;
import com.itheima.reggie.mapper.CategoryMapper;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import com.itheima.reggie.service.SetmealDishService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private SetmealDishService setmealDishService;


    @Transactional
    public void saveDishWithFlavor(DishDto dishDto) {

        //添加菜品
        this.save(dishDto);
        //添加口味
        //添加口味里面菜品id
        Long id = dishDto.getId();
        List<DishFlavor> flavors = dishDto.getFlavors();
        for (DishFlavor flavor : flavors) {
            flavor.setDishId(id);
        }
        //保存口味
        dishFlavorService.saveBatch(flavors);
        //添加菜品应该把缓存里菜品对应的分类列表清空

        Set keys = redisTemplate.keys(LoginCode.DISHLIST_REDIS_KEY + dishDto.getCategoryId() + "*");
        redisTemplate.delete(keys);
        Set keys1 = redisTemplate.keys(LoginCode.DISHLIST_REDIS_KEY +  "null*");
        redisTemplate.delete(keys1);
    }

    @Override
    public Page<DishDto> pageDishWithCategory(Integer page, Integer pageSize, String name) {
        //分页查询菜品
        Page<Dish> dishPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.isNotEmpty(name), Dish::getName, name).
                orderByDesc(Dish::getUpdateTime);

        this.page(dishPage, lambdaQueryWrapper);

        //菜品表没有分类名称,dishDto有
        Page<DishDto> dishDtoPage = new Page<>();
        BeanUtils.copyProperties(dishPage, dishDtoPage);
        List<DishDto> dishDtoList = new ArrayList<>();
        dishDtoPage.setRecords(dishDtoList);

        //根据菜品表里的分类id进行查找,然后将找到的值放在一个集合里
        List<Dish> dishs = dishPage.getRecords();

        //方式二
//        if (dishs.size() == 0){
//            return dishDtoPage;
//        }


        Set<Long> ids = new HashSet<>();
        for (Dish dish : dishs) {
            ids.add(dish.getCategoryId());
        }

        //到分类表里面查找
//      方式一
        LambdaQueryWrapper<Category> categoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
        categoryLambdaQueryWrapper.in(ids.size() > 0, Category::getId, ids);
        //根据传输的id集合查询到的所有分类信息
        List<Category> categorys = categoryMapper.selectList(categoryLambdaQueryWrapper);
        //方式二
        //     List<Category> categorys  =   categoryMapper.selectBatchIds(ids);


        //遍历dishs数组和categorys数组
        for (Dish dish : dishs) {

            for (Category category : categorys) {
                if (dish.getCategoryId().equals(category.getId())) {
                    //匹配成功则存入到dishDto里面
                    DishDto dishDto = new DishDto();
                    dishDto.setCategoryName(category.getName());
                    BeanUtils.copyProperties(dish, dishDto);
                    dishDtoList.add(dishDto);
                    break;
                }
            }
        }
        return dishDtoPage;
    }

    /**
     * 根据菜品id回显数据
     *
     * @param id
     * @return
     */
    @Override
    public DishDto getDishWithFlavor(Long id) {
        DishDto dishDto = new DishDto();
        //根据id查找dish,flavor,category
        Dish dish = this.getById(id);
        BeanUtils.copyProperties(dish, dishDto);
        //flavor表里的dishid

        List<DishFlavor> dishFlavors = dishFlavorService.list(new LambdaQueryWrapper<DishFlavor>().eq(DishFlavor::getDishId, id));
        dishDto.setFlavors(dishFlavors);
//根据菜品里的分类id在category里面查找
//        Long categoryId = dish.getCategoryId();
//        Category category = categoryMapper.selectById(categoryId);
//        dishDto.setCategoryName(category.getName());
        return dishDto;
    }

    /**
     * 菜品修改
     *
     * @param dishDto
     */
    @Override
    @Transactional
    public void updateDishWithFlavor(DishDto dishDto) {
        //如果有人添加到了购物车也不能进行修改



        //存dish
        this.updateById(dishDto);
        //存口味,先删除在添加全部
        LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(DishFlavor::getDishId, dishDto.getId());
        dishFlavorService.remove(lambdaQueryWrapper);

        //添加全部,因为是新存的会没有菜品id所以要现存入菜品id
        List<DishFlavor> flavors = dishDto.getFlavors();
        for (DishFlavor flavor : flavors) {
            flavor.setDishId(dishDto.getId());
        }
        dishFlavorService.saveBatch(flavors);
//菜品一旦修改,对应菜品套餐关系表里的字段也要进行修改
        SetmealDish setmealDish = new SetmealDish();
        setmealDish.setName(dishDto.getName());
        setmealDish.setPrice(dishDto.getPrice());

        setmealDishService.update(setmealDish, new LambdaQueryWrapper<SetmealDish>().eq(SetmealDish::getDishId, dishDto.getId()));

//修改菜品应该把缓存里菜品对应的分类列表清空

        Set keys = redisTemplate.keys(LoginCode.DISHLIST_REDIS_KEY + dishDto.getCategoryId() + "*");
        redisTemplate.delete(keys);
        Set keys1 = redisTemplate.keys(LoginCode.DISHLIST_REDIS_KEY +  "null*");
        redisTemplate.delete(keys1);
    }

    /**
     * 根据dishid批量删除
     *
     * @param ids
     */
    @Override
    @Transactional
    public void deleteishWithFlavor(Long[] ids) {

        //方式1
//            List<Long> dishList = new ArrayList<>();
//            Collections.addAll(dishList,ids);
        //      this.removeByIds(dishList);
        //方式2


        //删除之前先判断是否禁用
        LambdaQueryWrapper<Dish> lqw1 = new LambdaQueryWrapper<>();
        lqw1.in(Dish::getId, ids).eq(Dish::getStatus, 1);

        int count = this.count(lqw1);
        if (count > 0) {

            throw new CustomException("菜品未禁用,不能删除");

        }

        //判断套餐中是否有该菜品
        LambdaQueryWrapper<SetmealDish> lqw2 = new LambdaQueryWrapper<>();
        lqw2.in(SetmealDish::getDishId, ids);
        count = setmealDishService.count(lqw2);
        if (count > 0) {

            throw new CustomException("套餐中有该菜品,不能删除");

        }
        //进行删除操作
        LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishLambdaQueryWrapper.in(Dish::getId, ids);

        this.remove(dishLambdaQueryWrapper);

        //在口味表里删除
        LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(DishFlavor::getDishId, ids);
        dishFlavorService.remove(lambdaQueryWrapper);
        //删除菜品应该把缓存里菜品对应的分类列表清空
        List<Long> idlist = new ArrayList<>();
        Collections.addAll(idlist,ids);
        List<Dish> dishList = this.listByIds(idlist);
        for (Dish dish : dishList) {
            redisTemplate.delete(redisTemplate.keys(LoginCode.DISHLIST_REDIS_KEY + dish.getCategoryId() + "*"));
        }

        Set keys1 = redisTemplate.keys(LoginCode.DISHLIST_REDIS_KEY +  "null*");
        redisTemplate.delete(keys1);

    }

    /**
     * 查询菜品以及口味信息
     *
     * @param name
     * @param categoryId
     * @param status
     * @return
     */
    @Override
    public List<DishDto> listWithFlavor(String name, Long categoryId, Integer status) {
        //先去缓存里面查找,有了就返回,没有就存入缓存

        String redisKey = LoginCode.DISHLIST_REDIS_KEY + categoryId + "_" + status + "_" + name;
        List<DishDto> dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(redisKey);
        if (dishDtoList != null) {
            return dishDtoList;
        }
        LambdaQueryWrapper<Dish> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.isNotBlank(name), Dish::getName, name)
                .eq(categoryId != null, Dish::getCategoryId, categoryId)
                .eq(status != null, Dish::getStatus, status)
                .orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        //查询到的菜品信息
        List<Dish> dishList = this.list(lqw);
        //创建保存菜品以及口味的集合
        List<DishDto> dtoList = new ArrayList<>();
        if (dishList.size() == 0) {
            return dtoList;
        }
        //根据菜品信息的id到口味表里查找对应的口味
        //获取菜品id集合
        Set<Long> dishIdSet = dishList.stream().map(Dish::getId).collect(Collectors.toSet());
        //到口味表进行查询
        LambdaQueryWrapper<DishFlavor> lqw1 = new LambdaQueryWrapper<>();
        lqw1.in(DishFlavor::getDishId, dishIdSet);

        List<DishFlavor> dishFlavors = dishFlavorService.list(lqw1);

        for (Dish dish : dishList) {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(dish, dishDto);
            for (DishFlavor dishFlavor : dishFlavors) {
                if (dish.getId().equals(dishFlavor.getDishId())) {
                    //比对上就存入
                    dishDto.getFlavors().add(dishFlavor);

                }
            }
            //把dishdto存到集合dtoList
            dtoList.add(dishDto);
        }

        //没有就存一下
        redisTemplate.opsForValue().set(redisKey,dtoList,1L, TimeUnit.HOURS);
        return dtoList;
    }


}
